#include "altmaterialwidget.h"

#include "altapplication.h"
#include "altglobals.h"

#include <QAction>
#include <QFileDialog>
#include <QGridLayout>
#include <QHeaderView>
#include <QInputDialog>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QSet>
#include <QSettings>
#include <QTableWidget>
#include <QTableWidgetItem>

#include <climits>

#include <QtDebug>

namespace Alt {
     MaterialWidget::MaterialWidget(bool readOnly, QWidget* parent) : QWidget(parent) {
          init();
          setReadOnly(readOnly);
     }

     bool MaterialWidget::readOnly() const {
          return m_readOnly;
     }

     void MaterialWidget::setReadOnly(bool readOnly){
          if (readOnly != m_readOnly) {
               m_readOnly = readOnly;
               m_saveButton->setEnabled(!m_readOnly);
               m_importButton->setEnabled(!m_readOnly);
          }
          return;
     }
     //public slots
     void MaterialWidget::goToMaterialId() {
          bool ok = false;
          int matId = QInputDialog::getInt(this, tr("Go to material ID"), tr("Material ID:"), 0, 0, LONG_MAX, 1, &ok);
          if (ok) {
               for (int r = 0; r < m_materialTableWidget->rowCount(); r++) {
                    QTableWidgetItem* matIdItem = m_materialTableWidget->item(r, 0);
                    if (matIdItem->data(Qt::EditRole).toInt() == matId) {
                         m_materialTableWidget->scrollToItem(matIdItem);
                         m_materialTableWidget->setCurrentItem(matIdItem);
                         return;
                    }
               }
               QMessageBox::warning(this, tr("Not found"), tr("The specified material ID could not be found."));
          }
          return;
     }

     void MaterialWidget::goToMaterialName() {
          bool ok = false;
          QString matName = QInputDialog::getText(this, tr("Go to material name"), tr("Material name:"), QLineEdit::Normal, QString(), &ok);
          if (ok) {
               for (int r = 0; r < m_materialTableWidget->rowCount(); r++) {
                    QTableWidgetItem* matNameItem = m_materialTableWidget->item(r, 1);
                    if (matNameItem->data(Qt::EditRole).toString() == matName) {
                         m_materialTableWidget->scrollToItem(matNameItem);
                         m_materialTableWidget->setCurrentItem(matNameItem);
                         return;
                    }
               }
               QMessageBox::warning(this, tr("Not found"), tr("The specified material name could not be found."));
          }
          return;
     }

     void MaterialWidget::exportMaterials() {
          QString mdbFilter = tr("Material names file (*.mdb)");
          QString filter = tr("Material names file (*.mdb);;All files (*.*)");
          QString selectedFilter = mdbFilter;
          QString fileName = QFileDialog::getSaveFileName(this, tr("Export"), QString(), filter, &selectedFilter);
          if (fileName != "") {
               if ((selectedFilter == mdbFilter) && (!fileName.endsWith(".mdb"))) {
                    fileName.append(".mdb");
               }
               bool ok = Application::exportMaterialNames(fileName);
               if (!ok) {
                    QMessageBox::critical(this, tr("Error"), tr("Could not export to %1").arg(fileName));
               } else {
                    QMessageBox::information(this, tr("Success"), tr("Successfully exported material names."));
               }
          }
          return;
     }

     void MaterialWidget::importMaterials() {
          QString filter = tr("Material names file (*.mdb);;All files (*.*)");
          QString fileName = QFileDialog::getOpenFileName(this, tr("Import"), QString(), filter);
          if (fileName != "") {
               bool ok = Application::importMaterialNames(fileName);
               if (!ok) {
                    QMessageBox::critical(this, tr("Error"), tr("Could not import from %1").arg(fileName));
               } else {
                    refreshMaterials();
                    QMessageBox::information(this, tr("Success"), tr("Successfully imported material names."));
               }
          }
          return;
     }

     void MaterialWidget::insertMaterial() {
          int row = -1;
          int prevMatId = -1;
          if (m_materialTableWidget->rowCount() != 0) {
               m_materialTableWidget->insertRow(m_materialTableWidget->currentRow() + 1);
               row = m_materialTableWidget->currentRow();
               prevMatId = m_materialTableWidget->item(row, 0)->data(Qt::EditRole).toInt();
          } else {
               m_materialTableWidget->insertRow(0);
          }

          QTableWidgetItem* newMatIdItem = new QTableWidgetItem();
          newMatIdItem->setData(Qt::EditRole, (int)prevMatId + 1);

          QTableWidgetItem* newMatNameItem = new QTableWidgetItem();
          newMatNameItem->setData(Qt::EditRole, QString(""));

          m_materialTableWidget->setItem(row + 1, 0, newMatIdItem);
          m_materialTableWidget->setItem(row + 1, 1, newMatNameItem);
          m_materialTableWidget->setCurrentItem(newMatNameItem);
          return;
     }

     void MaterialWidget::materialTableContextMenu(const QPoint& pos) {
          if (m_readOnly) {
               m_materialTableContextMenuReadOnly->exec(m_materialTableWidget->viewport()->mapToGlobal(pos));
          } else {
               m_materialTableContextMenu->exec(m_materialTableWidget->viewport()->mapToGlobal(pos));
          }
          return;
     }

     void MaterialWidget::refreshMaterials() {
          m_materialTableWidget->clearContents();
          Application::refreshMaterialNames();
          QHash<int, QString> materialNames = Application::materialNames();
          m_materialTableWidget->setRowCount(materialNames.count());
          m_materialTableWidget->setSortingEnabled(false);
          int row = 0;
          for (QHash<int, QString>::ConstIterator i = materialNames.begin(); i != materialNames.end(); ++i) {
               QTableWidgetItem* idItem = new QTableWidgetItem();
               idItem->setData(Qt::EditRole, i.key());
               QTableWidgetItem* nameItem = new QTableWidgetItem();
               nameItem->setData(Qt::EditRole, i.value());
               m_materialTableWidget->setItem(row, 0, idItem);
               m_materialTableWidget->setItem(row, 1, nameItem);
               row++;
          }
          m_materialTableWidget->setSortingEnabled(true);
          return;
     }

     void MaterialWidget::removeMaterial() {
          m_materialTableWidget->removeRow(m_materialTableWidget->currentItem()->row());
          return;
     }

     void MaterialWidget::saveMaterials() {
          QSet<int> conflictingIdSet;
          QHash<int, QString> matNames;
          for (int r = 0; r < m_materialTableWidget->rowCount(); r++) {
               int matId = m_materialTableWidget->item(r, 0)->data(Qt::EditRole).toInt();
               QString matName = m_materialTableWidget->item(r, 1)->data(Qt::EditRole).toString();
               if (matNames.contains(matId)) {
                    conflictingIdSet.insert(matId);
               }
               matNames.insert(matId, matName);
          }
          if (!conflictingIdSet.isEmpty()) {
               QList<int> conflictingIdList = conflictingIdSet.toList();
               qSort(conflictingIdList);
               QString conflictingIdString;
               foreach (int id, conflictingIdList) {
                    conflictingIdString += QString("%1, ").arg(id);
               }
               conflictingIdString.chop(2);
               QString errorMessage = tr("Cannot save, the following material ID(s) have multiple names assigned: %1.").arg(conflictingIdString);
               QMessageBox::critical(this, tr("Conflicting material IDs"), errorMessage);
          } else {
               QSettings* settings = Alt::settings();
               settings->beginGroup("global");
               settings->beginGroup("materials");
               settings->remove("");
               for (QHash<int, QString>::ConstIterator i = matNames.begin(); i != matNames.end(); ++i) {
                    settings->setValue(QString::number(i.key()), i.value());
               }
               settings->endGroup();
               settings->endGroup();
               delete settings;
               Application::refreshMaterialNames();
               QMessageBox::information(this, tr("Success"), tr("Successfully saved material names."));
          }
          return;
     }

     //private
     void MaterialWidget::init() {
          setWindowTitle(tr("Materials"));

          //Layout widgets
          m_materialTableWidget = new QTableWidget(this);
          m_materialTableWidget->setColumnCount(2);
          m_materialTableWidget->setHorizontalHeaderLabels(QStringList() << tr("ID") << tr("Name"));
          m_materialTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
          m_materialTableWidget->setSortingEnabled(true);
          m_materialTableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
          connect(m_materialTableWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(materialTableContextMenu(const QPoint&)));

          m_refreshButton = new QPushButton(tr("Refresh"), this);
          connect(m_refreshButton, SIGNAL(released()), this, SLOT(refreshMaterials()));

          m_saveButton = new QPushButton(tr("Save"), this);
          connect(m_saveButton, SIGNAL(released()), this, SLOT(saveMaterials()));

          m_importButton = new QPushButton(tr("Import"), this);
          connect(m_importButton, SIGNAL(released()), this, SLOT(importMaterials()));

          m_exportButton = new QPushButton(tr("Export"), this);
          connect(m_exportButton, SIGNAL(released()), this, SLOT(exportMaterials()));

          QGridLayout* layout = new QGridLayout(this);
          layout->addWidget(m_materialTableWidget, 0, 0, 1, 2);
          layout->addWidget(m_refreshButton, 1, 0, 1, 1);
          layout->addWidget(m_saveButton, 1, 1, 1, 1);
          layout->addWidget(m_importButton, 2, 0, 1, 1);
          layout->addWidget(m_exportButton, 2, 1, 1, 1);

          //Initialize menus
          QAction* goToMaterialIdAction = new QAction(tr("Go to material ID"), this);
          connect(goToMaterialIdAction, SIGNAL(triggered()), this, SLOT(goToMaterialId()));

          QAction* goToMaterialNameAction = new QAction(tr("Go to material name"), this);
          connect(goToMaterialNameAction, SIGNAL(triggered()), this, SLOT(goToMaterialName()));

          QAction* insertAction = new QAction(tr("Insert"), this);
          connect(insertAction, SIGNAL(triggered()), this, SLOT(insertMaterial()));

          QAction* removeAction = new QAction(tr("Remove"), this);
          connect(removeAction, SIGNAL(triggered()), this, SLOT(removeMaterial()));

          m_materialTableContextMenuReadOnly = new QMenu(this);
          m_materialTableContextMenuReadOnly->addAction(goToMaterialIdAction);
          m_materialTableContextMenuReadOnly->addAction(goToMaterialNameAction);

          m_materialTableContextMenu = new QMenu(this);
          m_materialTableContextMenu->addAction(insertAction);
          m_materialTableContextMenu->addAction(removeAction);
          m_materialTableContextMenu->addActions(m_materialTableContextMenuReadOnly->actions());

          //Load entries
          refreshMaterials();
          m_materialTableWidget->sortByColumn(0, Qt::AscendingOrder);
          return;
     }

}
